package com.crawler.util.template;

import com.crawler.util.StrKit;

import java.util.LinkedList;
import java.util.List;

/**
 * Created by p on 2015/6/12.
 */
public class URLTemplate {

    public static final String PATTERN_DIGITAL = "[d]";

    public static final String PATTERN_ALL = "[*]";

    /**
     * 匹配值
     **/
    public static final int CONST_MATCH = 111;

    public static final int DIGITAL_MATCH = 11;

    public static final int ALL_MATCH = 1;

    public static final int NOT_MATCH = -1;

    private String host;

    /**
     * 可以为空，只匹配主机名
     */
    private List<String> paths = new LinkedList<>();

    /**
     * html\php\jsp\asp
     */
    private String doctype;

    public URLTemplate(String host) {
        this.host = host;
    }

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public List<String> getPaths() {
        return paths;
    }

    public void setPaths(List<String> paths) {
        this.paths = paths;
    }

    public String getDoctype() {
        return doctype;
    }

    public void setDoctype(String doctype) {
        this.doctype = doctype;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder(host);
        builder.append(URLTemplateBuilder.PATH_SEP);
        for (String p : paths) {
            builder.append(p).append(URLTemplateBuilder.PATH_SEP);
        }
        builder.deleteCharAt(builder.length() - 1);
        if (doctype != null && !doctype.isEmpty()) {
            builder.append(".").append(doctype);
        }
        return builder.toString();
    }

    /**
     * 检测当前URL模版，是否匹配URL，匹配逻辑如下： 1. host 一致 2. 如果存在doctype，必须相等 3. path长度一致 4.
     * path对应的每一段范围必须比URL大
     *
     * @param url url
     * @return 返回匹配结果，越高越好，返回-1表示不匹配
     */
    public MatchResult match(String url) {
        URLTemplate template = URLTemplateBuilder.build(url);
        if (!getHost().equals(template.getHost())) {
            return new MatchResult(URLTemplate.NOT_MATCH, this);
        }
        if (!StrKit.isEmpty(getDoctype()) && !getDoctype().equals(URLTemplate.PATTERN_ALL)
                && !getDoctype().equalsIgnoreCase(template.getDoctype())) {
            return new MatchResult(URLTemplate.NOT_MATCH, this);
        }
        if (getPaths().size() != template.getPaths().size()) {
            return new MatchResult(URLTemplate.NOT_MATCH, this);
        }
        int len = getPaths().size();
        int value = 0;
        for (int i = 0; i < len; i++) {
            String p1 = getPaths().get(i);
            String p2 = template.getPaths().get(i);
            int match = match(p2, p1);
            if (match != NOT_MATCH) {
                value += match;
            } else {
                value = NOT_MATCH;
                break;
            }
        }
        return new MatchResult(value, this);
    }

    /**
     * 向前兼容算法：
     * <p>
     * 对于形似http://news.stnn.cc/hongkong/2015-07/02/221524.shtml这种url
     * <p>
     * 旧的模版算法生成URL模版为news.stnn.cc/hongkong/[d]/[d]/[d].shtml
     * <p>
     * 新版算法生成URL模版为news.stnn.cc/hongkong/[d]-[d]/[d]/[d].shtml
     * <p>
     * 兼容处理：当模式串为[d]的时候，如果目标串为[d]-[d]-[d]则认为匹配
     */
    int match(String target, String pattern) {
        if (pattern.equals(URLTemplate.PATTERN_ALL)) {
            return ALL_MATCH;
        }
        if (pattern.equals(URLTemplate.PATTERN_DIGITAL)) {
            if (target.equals(URLTemplate.PATTERN_DIGITAL)) {
                return DIGITAL_MATCH;
            } else {
                if (allDigitalPattern(target)) {
                    return DIGITAL_MATCH;
                }
            }
            return NOT_MATCH;
        }
        int ch = target.indexOf('-');
        if (ch != -1) {
            return matchWithSplit(target, pattern, "-");
        }

        ch = target.indexOf('_');
        if (ch != -1) {
            return matchWithSplit(target, pattern, "_");
        }
        if (target.equals(pattern)) {
            return CONST_MATCH;
        }
        return NOT_MATCH;
    }

    boolean allDigitalPattern(String p) {
        String[] ss = p.split("-|_");
        for (String s : ss) {
            if (!s.equals(PATTERN_DIGITAL)) {
                return false;
            }
        }
        return true;
    }

    int matchWithSplit(String target, String pattern, String splitChar) {
        String[] s1 = pattern.split(splitChar);
        String[] s2 = target.split(splitChar);
        if (s1.length != s2.length) {
            return URLTemplate.NOT_MATCH;
        }
        int v = 0;
        for (int j = 0; j < s2.length; j++) {
            int rs = match(s2[j], s1[j]);
            if (rs == NOT_MATCH) {
                return NOT_MATCH;
            }
            v += rs;
        }
        return v;
    }
}
